{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Regressão Linear Simples - Trabalho\n",
    "\n",
    "## Estudo de caso: Seguro de automóvel sueco\n",
    "\n",
    "Agora, sabemos como implementar um modelo de regressão linear simples. Vamos aplicá-lo ao conjunto de dados do seguro de automóveis sueco. Esta seção assume que você baixou o conjunto de dados para o arquivo insurance.csv, o qual está disponível no notebook respectivo.\n",
    "\n",
    "O conjunto de dados envolve a previsão do pagamento total de todas as reclamações em milhares de Kronor sueco, dado o número total de reclamações. É um dataset composto por 63 observações com 1 variável de entrada e 1 variável de saída. Os nomes das variáveis são os seguintes:\n",
    "\n",
    "1. Número de reivindicações.\n",
    "2. Pagamento total para todas as reclamações em milhares de Kronor sueco.\n",
    "\n",
    "Voce deve adicionar algumas funções acessórias à regressão linear simples. Especificamente, uma função para carregar o arquivo CSV chamado *load_csv ()*, uma função para converter um conjunto de dados carregado para números chamado *str_column_to_float ()*, uma função para avaliar um algoritmo usando um conjunto de treino e teste chamado *split_train_split ()*, a função para calcular RMSE chamado *rmse_metric ()* e uma função para avaliar um algoritmo chamado *evaluate_algorithm()*.\n",
    "\n",
    "Utilize um conjunto de dados de treinamento de 60% dos dados para preparar o modelo. As previsões devem ser feitas nos restantes 40%. \n",
    "\n",
    "Compare a performabce do seu algoritmo com o algoritmo baseline, o qual utiliza a média dos pagamentos realizados para realizar a predição ( a média é 72,251 mil Kronor).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 441,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Bibliotecas \n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.model_selection import train_test_split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 442,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Reclamações</th>\n",
       "      <th>Kronor</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>108</td>\n",
       "      <td>392.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>19</td>\n",
       "      <td>46.2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>13</td>\n",
       "      <td>15.7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>124</td>\n",
       "      <td>422.2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>40</td>\n",
       "      <td>119.4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Reclamações  Kronor\n",
       "0          108   392.5\n",
       "1           19    46.2\n",
       "2           13    15.7\n",
       "3          124   422.2\n",
       "4           40   119.4"
      ]
     },
     "execution_count": 442,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Carrega os dados\n",
    "dataset = pd.read_csv('insurance.csv', names=['Reclamações','Kronor'])\n",
    "dataset.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 443,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Classe da regressão linear univariada\n",
    "class simple_linear_regression(object):\n",
    "    \n",
    "    def __init__(self):\n",
    "        self.b0 = None\n",
    "        self.b1 = None\n",
    "    \n",
    "    def fit(self,train):\n",
    "        self.b0, self.b1 = self.coefficients(train)\n",
    "        \n",
    "    def predict(self, test):\n",
    "        predictions = []\n",
    "        for row in test:\n",
    "            ypred = self.b0 + self.b1 * row\n",
    "            predictions.append(ypred)\n",
    "        return predictions\n",
    "    \n",
    "    # Calculate coefficients\n",
    "    def coefficients(self, dataset):\n",
    "        x = dataset.iloc[:,0]\n",
    "        y = dataset.iloc[:,1]\n",
    "        x_mean, y_mean = self.mean(x), self.mean(y)\n",
    "        b1 = self.covariance(x, x_mean, y, y_mean) / self.variance(x, x_mean)\n",
    "        b0 = y_mean - b1 * x_mean\n",
    "        return [b0, b1]\n",
    "    \n",
    "    # Calculate covariance between x and y\n",
    "    def covariance(self, x, mean_x, y, mean_y):\n",
    "        covar = 0.0\n",
    "        for i in range(len(x)):\n",
    "            covar += (x.iloc[i] - mean_x) * (y.iloc[i] - mean_y)\n",
    "        return covar\n",
    "    \n",
    "    # Calculate the variance of a list of numbers\n",
    "    def variance(self, values, mean):\n",
    "        return sum([(x-mean)**2 for x in values])\n",
    "\n",
    "    # Calculate the mean value of a list of numbers\n",
    "    def mean(self, values):\n",
    "        return sum(values) / float(len(values))\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 444,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Separa o dataset em teste e treino\n",
    "data_train, data_test = train_test_split(dataset, test_size=0.40)\n",
    "#Separa os dados de teste em X e y\n",
    "X_test = data_test.iloc[:,0]\n",
    "y_test = data_test.iloc[:,1]\n",
    "y_list = y_test.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 445,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Executa a regressão linear e prediz os valores para X_test\n",
    "lr = simple_linear_regression()\n",
    "lr.fit(data_train)\n",
    "predict = lr.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 446,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from math import sqrt\n",
    "\n",
    "# Calculate root mean squared error\n",
    "def rmse_metric(actual, predicted):\n",
    "    sum_error = 0.0\n",
    "    for i in range(len(actual)):\n",
    "        prediction_error = predicted[i] - actual[i]\n",
    "        sum_error += (prediction_error ** 2)\n",
    "        mean_error = sum_error / float(len(actual))\n",
    "    return sqrt(mean_error)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 447,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Calcula o RMSE para o algoritmo de regressão\n",
    "rmse_reg = rmse_metric(y_list,predict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 448,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import bisect as bs\n",
    "\n",
    "#Definição da função smart_mean\n",
    "#Essa função faz uma aproximação linear entre os dois valores mais próximos, no conjunto de treino, \n",
    "#em relação a amostra de teste\n",
    "def smart_mean(data_train,test):\n",
    "    data_sort = data_train.sort_values(data_train.columns[0], ascending = True)\n",
    "    X_train = (data_sort.iloc[:,0]).tolist()\n",
    "    y_train = (data_sort.iloc[:,1]).tolist()\n",
    "    predict = []\n",
    "    for x in test:\n",
    "        bigger = bs.bisect_right(X_train,x)\n",
    "        smaller = bs.bisect_left(X_train,x)\n",
    "        if(bigger > len(X_train)-1):\n",
    "            valuePredict = (x*y_train[smaller-1])/X_train[smaller-1]\n",
    "        else:\n",
    "            dif_x = (X_train[bigger] - X_train[smaller])\n",
    "            if(dif_x != 0):\n",
    "                incValue = (y_train[bigger] - y_train[smaller]) / dif_x\n",
    "                valuePredict = y_train[smaller] + dif_x*incValue\n",
    "            else:\n",
    "                valuePredict = y_train[smaller]\n",
    "        predict.append(valuePredict)\n",
    "    return predict\n",
    "\n",
    "#Definição da função baseline, prediz que todos os valores são a média dos dados de treino\n",
    "def baseline(y_train, test):\n",
    "    meanValue = np.mean(y_train)\n",
    "    predictions = [meanValue for i in range(len(test))]\n",
    "    return predictions\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 449,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Calcula o RMSE para o algoritmo de smart_mean\n",
    "predict_smartmean = smart_mean(data_train,X_test)\n",
    "rmse_smart = rmse_metric(y_list,predict_smartmean)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 450,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Calcula o RMSE para o algoritmo baseline\n",
    "predict_base = baseline(y_list,X_test)\n",
    "rmse_baseline = rmse_metric(y_list,predict_base)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 451,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predições\n",
      "valor real: 38.100\t|| regressão: 39.293\t|| smart_mean: 40.300\t|| baseline: 86.973\n",
      "valor real: 92.600\t|| regressão: 116.396\t|| smart_mean: 133.300\t|| baseline: 86.973\n",
      "valor real: 31.900\t|| regressão: 69.464\t|| smart_mean: 95.500\t|| baseline: 86.973\n",
      "valor real: 21.300\t|| regressão: 62.759\t|| smart_mean: 58.100\t|| baseline: 86.973\n",
      "valor real: 134.900\t|| regressão: 106.339\t|| smart_mean: 133.300\t|| baseline: 86.973\n",
      "valor real: 69.200\t|| regressão: 109.692\t|| smart_mean: 133.300\t|| baseline: 86.973\n",
      "valor real: 187.500\t|| regressão: 113.044\t|| smart_mean: 133.300\t|| baseline: 86.973\n",
      "valor real: 20.900\t|| regressão: 42.645\t|| smart_mean: 50.900\t|| baseline: 86.973\n",
      "valor real: 152.800\t|| regressão: 149.920\t|| smart_mean: 73.400\t|| baseline: 86.973\n",
      "valor real: 113.000\t|| regressão: 102.987\t|| smart_mean: 137.900\t|| baseline: 86.973\n",
      "valor real: 162.800\t|| regressão: 210.261\t|| smart_mean: 170.900\t|| baseline: 86.973\n",
      "valor real: 59.600\t|| regressão: 79.521\t|| smart_mean: 142.100\t|| baseline: 86.973\n",
      "valor real: 39.900\t|| regressão: 35.941\t|| smart_mean: 11.800\t|| baseline: 86.973\n",
      "valor real: 13.200\t|| regressão: 35.941\t|| smart_mean: 11.800\t|| baseline: 86.973\n",
      "valor real: 98.100\t|| regressão: 92.930\t|| smart_mean: 161.500\t|| baseline: 86.973\n",
      "valor real: 103.900\t|| regressão: 123.101\t|| smart_mean: 194.500\t|| baseline: 86.973\n",
      "valor real: 119.400\t|| regressão: 159.977\t|| smart_mean: 73.400\t|| baseline: 86.973\n",
      "valor real: 392.500\t|| regressão: 387.935\t|| smart_mean: 422.200\t|| baseline: 86.973\n",
      "valor real: 15.700\t|| regressão: 69.464\t|| smart_mean: 95.500\t|| baseline: 86.973\n",
      "valor real: 27.900\t|| regressão: 49.350\t|| smart_mean: 52.100\t|| baseline: 86.973\n",
      "valor real: 0.000\t|| regressão: 25.884\t|| smart_mean: 6.600\t|| baseline: 86.973\n",
      "valor real: 181.300\t|| regressão: 163.329\t|| smart_mean: 214.000\t|| baseline: 86.973\n",
      "valor real: 76.100\t|| regressão: 52.702\t|| smart_mean: 52.100\t|| baseline: 86.973\n",
      "valor real: 55.600\t|| regressão: 52.702\t|| smart_mean: 52.100\t|| baseline: 86.973\n",
      "valor real: 4.400\t|| regressão: 35.941\t|| smart_mean: 11.800\t|| baseline: 86.973\n",
      "valor real: 48.700\t|| regressão: 56.055\t|| smart_mean: 65.300\t|| baseline: 86.973\n"
     ]
    }
   ],
   "source": [
    "print('Predições')\n",
    "for i in range(len(y_list)):\n",
    "    print(\"valor real: {:.3f}\\t|| regressão: {:.3f}\\t|| smart_mean: {:.3f}\\t|| baseline: {:.3f}\".format(y_list[i], predict[i], predict_smartmean[i], predict_base[i]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 453,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE para regressão linear: 30.045630942473696\n",
      "RMSE para smart_mean: 45.49237045077745\n",
      "RMSE para baseline: 82.09841447776755\n"
     ]
    }
   ],
   "source": [
    "print('RMSE para regressão linear: {0}'.format(rmse_reg))\n",
    "print('RMSE para smart_mean: {0}'.format(rmse_smart))\n",
    "print('RMSE para baseline: {0}'.format(rmse_baseline))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Criei uma função chamada de smart_mean, para fazer uma aproximação linear entre os valores mais próximos da variável a ser predita, presentes conjunto de treino. Pois o algoritmo de baseline somente tira a média dos valores de treino, dando uma aproximação muito ruim.\n",
    "\n",
    "Acima é possível ver o RMSE para os três exemplos propostos.\n",
    "\n",
    "O resultado varia de acordo com a execução, já que o dataset é separado de forma aleátoria, e são poucas amostras de treino. Mas em média a regressão linear deu o melhor resultado, seguido pelo smart_mean e depois pelo baseline"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
